//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this sample source code is subject to the terms of the Microsoft
// license agreement under which you licensed this sample source code. If
// you did not accept the terms of the license agreement, you are not
// authorized to use this sample source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the LICENSE.RTF on your install media or the root of your tools installation.
// THE SAMPLE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES OR INDEMNITIES.
//

#include <windows.h>
#include <minshell.h>
#include <resource.h>
#include <commctrl.h>
#include <string.hxx>
#include <vector.hxx>
#include <stdlib.h>
#include <algorithm>
using namespace std;

/* in minshell.h:
#define REGISTRY_SETTINGS _T("Software\\Compact13Tools\\Shell\\Minshell")
#define BACKGROUND_BITMAP_REGISTRY_VALUE _T("DesktopImage")
#define BACKGROUND_BITMAP_DEFAULT _T("\\Windows\\desktop.bmp")
#define BACKGROUND_RGB_KEY _T("Background_Color")
#define BACKGROUND_RGB_DEFAULT RGB(0,188,242)
*/





HINSTANCE           g_hInstance;
HWND                g_hwndDesktop = NULL;
HWND                g_hWndCommandBar;    // command bar handle
HMENU               g_hWndMenuMar;
HMENU               g_hWndPopupMenu;
HBRUSH				g_brush = NULL;



static HBITMAP      g_hBackgroundBmp = NULL;
static HANDLE       g_hShellAPI = NULL;

//struct CommandInfo
//{
//    ce::wstring Name;
//    ce::wstring App;
//    ce::wstring Param;
//};

class CommandInfo

{

public:ce::wstring Name;
public:ce::wstring App;
public:ce::wstring Param;

	   friend bool operator<(const CommandInfo& left,

		   const CommandInfo& right);

};

bool operator<(const CommandInfo& left,

	const CommandInfo& right)

{

	return left.Name < right.Name;

}


ce::vector<CommandInfo> g_arrCommandsFromReg;  // commands read from registry

// Window proc for desktop
static LRESULT Desktop_WindowProc(
	HWND hWnd,
	UINT uMsg,
	WPARAM wParam,
	LPARAM lParam
	)
{
	LRESULT lResult = 0;
	int wmId, wmEvent;
	BOOL fSuccess = FALSE;
	if (Desktop_WindowProcHook(hWnd, uMsg, wParam, lParam, &lResult))
		return lResult;

	switch (uMsg)
	{
	case WM_COMMAND:
		wmId = LOWORD(wParam);
		wmEvent = HIWORD(wParam);
		if (wmId >= IDR_MENU_BASE && wmId < IDR_MENU_BASE + g_arrCommandsFromReg.size())
		{
			CreateProcess(g_arrCommandsFromReg[wmId - IDR_MENU_BASE].App,
				wcslen(g_arrCommandsFromReg[wmId - IDR_MENU_BASE].Param)>0 ? g_arrCommandsFromReg[wmId - IDR_MENU_BASE].Param : NULL,
				NULL, NULL, FALSE, 0, NULL, NULL, NULL, NULL);
		}
#ifdef DEBUG
		else if (wmId == IDR_MENU_BASE + g_arrCommandsFromReg.size() + 1)
		{
			DestroyWindow(g_hwndDesktop);
		}
#endif
		break;
	case WM_CREATE:
	{
		// Change window size to fill the full screen!
		RECT rc = { 0, 0, 0, 0 };
		SystemParametersInfo(SPI_GETWORKAREA, NULL, &rc, NULL);
		if (!MoveWindow(hWnd, 0, 0, rc.right, rc.bottom, TRUE))
		{
			DWORD dwErr = GetLastError();
			RETAILMSG(1, (L"MoveWindow failed error=0x%X", dwErr));
		}

		Desktop_CreateMenus(hWnd);
	}
		break;

	case WM_ACTIVATE:
		if (LOWORD(wParam) && GetForegroundWindow() == g_hwndDesktop)
		{
			SetFocus(g_hwndDesktop);
		}
		break;

	case WM_PAINT:
	{
		PAINTSTRUCT ps = { 0 };

		HDC hdcWnd = BeginPaint(hWnd, &ps);
		if (hdcWnd && ps.fErase)
		{
			if (g_brush)
			{
				FillRect(ps.hdc, &ps.rcPaint, g_brush);
			}

			// Paint desktop bitmap...
			if (g_hBackgroundBmp)
			{
				// Blt bitmap in the center of the new white memory dc
				HDC hdcBmp = CreateCompatibleDC(hdcWnd);
				if (hdcBmp)
				{
					HBITMAP hOldBmp = (HBITMAP)SelectObject(hdcBmp, g_hBackgroundBmp);

					RECT rcWindow;
					BITMAP bm;
					GetWindowRect(hWnd, &rcWindow);
					GetObject(g_hBackgroundBmp, sizeof(BITMAP), &bm);
					int x = (rcWindow.right - bm.bmWidth) / 2;
					int y = (rcWindow.bottom - bm.bmHeight) / 2;

					BitBlt(hdcWnd, x, y, bm.bmWidth, bm.bmHeight, hdcBmp, 0, 0, SRCCOPY);

					SelectObject(hdcBmp, hOldBmp);
					DeleteDC(hdcBmp);
				}
			}
		}

		//Desktop_WindowProc( hwnd, WM_DRAW, ps.hdc, 0 );
		EndPaint(hWnd, &ps);
	}
		break;

	case WM_WININICHANGE:
	{
		if (SPI_SETWORKAREA == wParam || SETTINGCHANGE_RESET == wParam)
		{
			RECT workArea;

			if (TRUE == SystemParametersInfo(SPI_GETWORKAREA, 0, &workArea, 0))
			{
				if (!MoveWindow(hWnd, workArea.left, workArea.top, workArea.right - workArea.left, workArea.bottom - workArea.top, TRUE))
				{
					DWORD dwErr = GetLastError();
					RETAILMSG(1, (L"MoveWindow failed error=0x%X", dwErr));
				}
				if (g_hWndCommandBar)
				{
					SendMessage(g_hWndCommandBar, TB_AUTOSIZE, 0, 0);
					CommandBar_AlignAdornments(g_hWndCommandBar);
				}
			}
			else
			{
				DWORD dwErr = GetLastError();
				RETAILMSG(1, (L"SystemParametersInfo failed error=0x%X", dwErr));
			}
		}
	}
		break;

	case WM_DESTROY:
		if (g_hWndPopupMenu)
		{
			DestroyMenu(g_hWndPopupMenu);
			g_hWndPopupMenu = NULL;
		}
		if (g_hWndMenuMar)
		{
			DestroyMenu(g_hWndMenuMar);
			g_hWndMenuMar = NULL;
		}
		if (g_hWndCommandBar)
		{
			CommandBar_Destroy(g_hWndCommandBar);
			g_hWndCommandBar = NULL;
		}

		PostQuitMessage(0);
		break;

	default:
		lResult = DefWindowProc(hWnd, uMsg, wParam, lParam);
		break;
	}
	return lResult;
}

static long res;

static BOOL Desktop_CreateWindow()
{
	RECT rcArea = { 0 };
	WNDCLASS wc = { 0 };

	wc.style = CS_HREDRAW | CS_VREDRAW;
	wc.lpfnWndProc = Desktop_WindowProc;
	wc.hInstance = g_hInstance;
	// IMPORTANT NOTE: The desktop window class name MUST be "DesktopExplorerWindow". 
	wc.lpszClassName = CLASSNAME_DESKTOP;
	RegisterClass(&wc);

	SystemParametersInfo(SPI_GETWORKAREA, 0, &rcArea, 0);
	g_hwndDesktop = CreateWindowEx(
		0,
		CLASSNAME_DESKTOP,
		L"Desktop",
		WS_VISIBLE,
		rcArea.left, rcArea.top, rcArea.right, rcArea.bottom,
		NULL,
		NULL,
		g_hInstance,
		0
		);
	return g_hwndDesktop ? TRUE : FALSE;
}

//nb: See nbs in following function
//#define LR_LOADFROMFILE 0x00000010

//Modified to use actual file specied in registry rather than resource as background image
//Registry key is HKLM\SOFTWARE\Compact13Tools, value DesktopImage
BOOL Desktop_Init(
	HINSTANCE hInstance
	)
{
	g_hInstance = hInstance;

	g_hShellAPI = RegisterShellAPI();
	if (!g_hShellAPI)
	{
		DEBUGMSG(1, (L"Failed to register shell API! \r\n"));
#if !defined( DEBUG )
		return FALSE;
#endif // !DEBUG
	}

	if (!Desktop_CreateWindow())
		return FALSE;

	g_brush = CreateSolidBrush(BACKGROUND_RGB_DEFAULT);


	//NB: LoadImage is recommended instaed of LoadBitMap on MSDN.. BUT (See next nb below).
	//g_hBackgroundBmp = LoadBitmap( hInstance, MAKEINTRESOURCE(IDB_DESKTOP) );//Resource method
	SetLastError(0);
	HKEY HKey;
	TCHAR  bitmapPath[MAXCHAR];
	BYTE bg_rgb[3];
	DWORD bg_rgb_len = 3;
	DWORD type;//
	DWORD len = MAXCHAR*sizeof(TCHAR);

	res = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
		REGISTRY_SETTINGS,
		0,
		KEY_QUERY_VALUE,
		&HKey);

	if (res == ERROR_SUCCESS)
	{
		res = RegQueryValueEx(HKey,
			BACKGROUND_RGB_KEY,
			NULL,
			&type,
			bg_rgb,
			&bg_rgb_len);

		//Set bg
		if (res == ERROR_SUCCESS)
			g_brush = CreateSolidBrush(RGB(bg_rgb[0], bg_rgb[1], bg_rgb[2]));

		res = RegQueryValueEx(HKey,
			BACKGROUND_BITMAP_REGISTRY_VALUE,
			NULL,
			&type,
			(LPBYTE)bitmapPath,
			&len);

		if (res == ERROR_SUCCESS)
			g_hBackgroundBmp = SHLoadDIBitmap(bitmapPath);
		//See NB below

		RegCloseKey(HKey);
	}
	if (res != ERROR_SUCCESS)
	{
		LPWSTR filename = BACKGROUND_BITMAP_DEFAULT;
		g_hBackgroundBmp = SHLoadDIBitmap(filename);
		//NB: LoadImage with LR_LOADFROMFILE does not work under CE
		//g_hBackgroundBmp =(HBITMAP) LoadImage( NULL, filename,IMAGE_BITMAP, 0, 0,LR_LOADFROMFILE );
	}

	if (!g_hBackgroundBmp) {
		DWORD errNo = GetLastError();
		RETAILMSG(!g_hBackgroundBmp, (_T("Failed to load desktop image! err = 0x%08x\r\n"), errNo));
	}


	if (!TaskBar_Start())
		return FALSE;

	SetForegroundWindow(g_hwndDesktop);
	return TRUE;
}

void Desktop_CalibrateTouch(
	void
	)
{
	// Using LoadLibaryEx to load CoreDll.dll module in address space of this process,
	// if needed. If module is already loaded, reference count for that module is incremented.
	// When FreeLibrary is called, reference count will be decremented. This is safer
	// than using GetModuleHandle, which does not increment reference count
	HMODULE hCoreDll = LoadLibraryEx(L"CoreDll.dll", NULL, 0);
	if (!hCoreDll)
	{
		DEBUGMSG(1, (L"Failed Call to LoadLibraryEx(\"CoreDll.dll\"). err = 0x%08x.\r\n", GetLastError()));
		ASSERT(hCoreDll);
		return;
	}

	FARPROC pfnTouchCalibrate = GetProcAddress(hCoreDll, L"TouchCalibrate");

	if (!pfnTouchCalibrate)
	{
		// No touch in GWES!
		return;
	}

	if (GetAsyncKeyState(VK_SHIFT))
	{
		// Bypassing calibration check
		FreeLibrary(hCoreDll);
		return;
	}

	// Calibrate touch panel if neccesary
	DWORD dw;
	DWORD dwType;
	HKEY hKey;

	if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE,
		L"HARDWARE\\DEVICEMAP\\TOUCH",
		0,
		0,
		&hKey))
	{
		dw = 0;
		if (ERROR_SUCCESS != RegQueryValueEx(hKey,
			L"CalibrationData",
			NULL,
			&dwType,
			NULL,
			&dw))
		{
			// No calibration data, attempting to calibrate
			pfnTouchCalibrate();
		}
		RegCloseKey(hKey);
		RegFlushKey(HKEY_LOCAL_MACHINE);
	}
	FreeLibrary(hCoreDll);
	return;
}

BOOL Desktop_CreateMenus(
	HWND hWnd)
{
	BOOL fSuccess = TRUE;
	int i = 0;

	Desktop_ReadCommandsFromReg();

	if (g_arrCommandsFromReg.size() <= 0)
	{
		fSuccess = FALSE;
		goto CleanExit;
	}

	g_hWndMenuMar = CreateMenu();
	g_hWndPopupMenu = CreatePopupMenu();


	std::sort(g_arrCommandsFromReg.begin(), g_arrCommandsFromReg.end());

	for (; i < g_arrCommandsFromReg.size(); i++)
	{
		AppendMenu(g_hWndPopupMenu, MF_STRING | MF_ENABLED, IDR_MENU_BASE + i, g_arrCommandsFromReg[i].Name);
	}
#ifdef DEBUG
	// In DEBUG builds, show a seperator-bar and Exit menu option
	if (i>0)
	{
		AppendMenu(g_hWndPopupMenu, MF_SEPARATOR, 0, NULL);
	}
	AppendMenu(g_hWndPopupMenu, MF_STRING | MF_ENABLED, IDR_MENU_BASE + i + 1, TEXT("&Exit"));
#endif
	AppendMenu(g_hWndMenuMar, MF_STRING | MF_ENABLED | MF_POPUP, (UINT)g_hWndPopupMenu, TEXT("&Command"));

	g_hWndCommandBar = CommandBar_Create(g_hInstance, hWnd, 1);
	CommandBar_InsertMenubarEx(g_hWndCommandBar, NULL, (LPTSTR)g_hWndMenuMar, 0);
#ifdef DEBUG
	// Only add the [X] close-button in top-right when using a DEBUG build
	CommandBar_AddAdornments(g_hWndCommandBar, 0, 0);
#endif

CleanExit:

	return fSuccess;
}

BOOL Desktop_ReadCommandsFromReg()
{
	BOOL fSuccess = TRUE;
	HKEY hKey = NULL;

	if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE,
		REGISTRY_SETTINGS,
		//L"Software\\Compact13Tools\\Shell\\Minshell", 
		0,
		0,
		&hKey))
	{
		DWORD dwIndex = 0;
		TCHAR szKeyName[MAX_PATH] = { 0 };
		DWORD cbName = MAX_PATH;

		if (ERROR_SUCCESS != RegQueryInfoKey(hKey, NULL, NULL, NULL, &dwIndex, NULL, NULL, NULL, NULL, NULL, NULL, NULL))
		{
			fSuccess = FALSE;
			goto CleanExit;
		}

		dwIndex = 0;
		while (ERROR_SUCCESS == RegEnumKeyEx(hKey, dwIndex, szKeyName, &cbName, NULL, NULL, NULL, NULL))
		{
			HKEY hSubKey = NULL;
			TCHAR szValue[MAX_PATH] = { 0 };
			DWORD dwType = 0;
			DWORD cData = MAX_PATH;

			g_arrCommandsFromReg.push_back(CommandInfo());

			if (ERROR_SUCCESS == RegOpenKeyEx(hKey, szKeyName, 0, 0, &hSubKey))
			{
				g_arrCommandsFromReg[dwIndex].Name = szKeyName;

				if (ERROR_SUCCESS == RegQueryValueEx(hSubKey, L"App", NULL, &dwType, (LPBYTE)szValue, &cData))
				{
					if (szValue[0] != 0)
					{
						g_arrCommandsFromReg[dwIndex].App = szValue;
					}
				}

				memset(szValue, 0, MAX_PATH);
				cData = MAX_PATH;
				if (ERROR_SUCCESS == RegQueryValueEx(hSubKey, L"Param", NULL, &dwType, (LPBYTE)szValue, &cData))
				{
					if (szValue[0] != 0)
					{
						g_arrCommandsFromReg[dwIndex].Param = szValue;
					}
				}

				RegCloseKey(hSubKey);
			}

			dwIndex++;
			cbName = MAX_PATH;
		}
	}

CleanExit:
	if (hKey)
	{
		RegCloseKey(hKey);
	}

	return fSuccess;
}

void Desktop_Uninit()
{
	TaskBar_Stop();

	if (g_hBackgroundBmp)
	{
		DeleteObject(g_hBackgroundBmp);
		g_hBackgroundBmp = NULL;
	}

	if (g_brush)
	{
		DeleteObject(g_brush);
		g_brush = NULL;
	}


	if (IsWindow(g_hwndDesktop))
	{
		DestroyWindow(g_hwndDesktop);
		g_hwndDesktop = NULL;
	}

	if (g_hShellAPI)
	{
		CloseHandle(g_hShellAPI);
		g_hShellAPI = NULL;
	}

	g_hInstance = NULL;
}
